package repository

import (
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntity"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntityManager"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Slice"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
)

type repoLocalOperateService struct {
}

func (e *repoLocalOperateService) selectEntityList(body map[string]interface{}) ([]commEntity.IEntity, error) {
	list := commEntityManager.FindEntityList(edgeEntity.Type.OperateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.OperateEntity)

		result := true

		if Map.Has(body, "deviceType") {
			result = result && entity.DeviceType == body["deviceType"]
		}
		if Map.Has(body, "manufacturer") {
			result = result && entity.Manufacturer == body["manufacturer"]
		}
		if Map.Has(body, "operateName") {
			result = result && entity.OperateName == body["operateName"]
		}
		if Map.Has(body, "operateMode") {
			result = result && entity.OperateMode == body["operateMode"]
		}
		if Map.Has(body, "operateModes") {
			operateModes := Map.GetOrDefault(body, "operateModes", make([]string, 0))
			result = result && Slice.Has(operateModes, entity.OperateMode)
		}
		if Map.Has(body, "dataType") {
			result = result && entity.DataType == body["dataType"]
		}
		if Map.Has(body, "serviceType") {
			result = result && entity.ServiceType == body["serviceType"]
		}
		if Map.Has(body, "engineType") {
			result = result && entity.EngineType == body["engineType"]
		}
		if Map.Has(body, "polling") {
			result = result && entity.Polling == body["polling"]
		}

		return result
	})

	return list, nil
}

func (e *repoLocalOperateService) GetOperateEntityList(compEntity *edgeEntity.RepoCompEntity) ([]commEntity.IEntity, error) {
	list := commEntityManager.FindEntityList(edgeEntity.Type.OperateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.OperateEntity)

		manufacturer := Map.GetString(compEntity.CompParam, "manufacturer", "")
		deviceType := Map.GetString(compEntity.CompParam, "deviceType", "")

		if entity.Manufacturer != manufacturer {
			return false
		}
		if entity.DeviceType != deviceType {
			return false
		}

		if "jar-decoder" == compEntity.CompType {
			return entity.EngineType == "Java"
		}
		if "jsp-decoder" == compEntity.CompType {
			return entity.EngineType == "JavaScript"
		}
		if "jsn-decoder" == compEntity.CompType {
			return entity.EngineType == "JsonScript"
		}

		return false
	})

	return list, nil
}

func (e *repoLocalOperateService) InsertOrUpdate(body map[string]interface{}) (interface{}, error) {
	// 提取业务参数
	compId := Map.GetInt64(body, "compId", 0)
	operateName := Map.GetString(body, "operateName", "")
	operateMode := Map.GetString(body, "operateMode", "")
	dataType := Map.GetString(body, "dataType", "")
	serviceType := Map.GetString(body, "serviceType", "")
	engineType := Map.GetString(body, "engineType", "")
	polling := Map.GetBool(body, "polling", false)
	timeout := Map.GetInt(body, "timeout", 2000)
	engineParam := Map.GetMap(body, "engineParam", nil)
	extendParam := Map.GetMap(body, "extendParam", nil)

	// 简单校验参数
	if Method.HasNull(compId, polling, timeout) {
		return nil, errors.New("参数不能为空: compId, polling, timeout")
	}
	if Method.HasEmpty(operateName, operateMode, dataType, serviceType, engineType) {
		return nil, errors.New("参数不能为空: operateName, operateMode, dataType, serviceType, engineType")
	}

	compEntity := commEntityManager.GetEntityById(edgeEntity.Type.RepoCompEntity.Type(), compId)
	if compEntity == nil {
		return nil, errors.New("找不到对应的组件: " + String.ToString(compId))
	}

	manufacturer := Map.GetString(compEntity.(*edgeEntity.RepoCompEntity).CompParam, "manufacturer", "")
	deviceType := Map.GetString(compEntity.(*edgeEntity.RepoCompEntity).CompParam, "deviceType", "")
	if Method.HasEmpty(manufacturer, deviceType) {
		return nil, errors.New("参数不能为空: manufacturer, deviceType")
	}

	// 构造作为参数的实体
	entity := edgeEntity.Type.OperateEntity.Instance()
	entity.DeviceType = deviceType
	entity.Manufacturer = manufacturer
	entity.EngineType = engineType
	entity.ServiceType = serviceType
	entity.Manufacturer = manufacturer
	entity.EngineParam = engineParam
	entity.ExtendParam = extendParam
	entity.OperateName = operateName
	entity.OperateMode = operateMode
	entity.DataType = dataType
	entity.Polling = polling
	entity.Timeout = timeout

	// 新增/修改实体：参数不包含id为新增，包含为修改
	if !Map.Has(body, "id") {
		// 如果没有填写，那么填入一个缺省值
		if Method.HasEmpty(entity.EngineParam) {
			entity.EngineParam = EngineParam.GetDefault(operateMode)
		}

		if entity.ExtendParam == nil {
			entity.ExtendParam = make(map[string]interface{})
		}
		if entity.EngineParam == nil {
			entity.EngineParam = make(map[string]interface{})
		}

		exist, err := commEntityManager.GetEntityByServiceKey(entity.Type(), entity.MakeServiceKey())
		if err != nil {
			return nil, err
		}
		if exist != nil {
			return nil, errors.New("实体已存在")
		}

		err = commEntityManager.InsertEntity(entity)
		if err != nil {
			return nil, err
		}

		return nil, nil
	} else {
		id := Map.GetInt64(body, "id", 0)

		exist := commEntityManager.GetEntityById(entity.Type(), id)
		if exist == nil {
			return nil, errors.New("实体不存在")
		}
		existEntity := exist.(*edgeEntity.OperateEntity)

		// 如果没有填写，说明只是修改标题，那么填入原来的数值
		if Method.HasEmpty(entity.EngineParam) {
			entity.EngineParam = existEntity.EngineParam
		}
		// 如果为空，那么说明用户不想修改该数据
		if Method.HasNull(entity.ExtendParam) {
			entity.ExtendParam = existEntity.ExtendParam
		}

		if manufacturer != existEntity.Manufacturer || deviceType != existEntity.DeviceType || engineType != existEntity.EngineType || operateName != existEntity.OperateName {
			return nil, errors.New("不允许修改，否则影响关联关系：manufacturer, deviceType, engineType, operateName")
		}

		// 修改数据
		entity.BaseEntity.Id = id
		entity.GetBaseEntity().CreateTime = exist.GetBaseEntity().CreateTime
		entity.GetBaseEntity().UpdateTime = exist.GetBaseEntity().UpdateTime
		return nil, commEntityManager.UpdateEntity(entity)
	}
}

func (e *repoLocalOperateService) DeleteEntity(id int64) {
	entity := commEntityManager.GetEntityById(edgeEntity.Type.OperateEntity.Type(), id)
	if entity == nil {
		return
	}

	err := commEntityManager.DeleteEntity(entity)
	if err != nil {
		return
	}
}

func (e *repoLocalOperateService) QueryEntity(id int64) *edgeEntity.OperateEntity {
	exist := commEntityManager.GetEntityById(edgeEntity.Type.OperateEntity.Type(), id)
	if exist == nil {
		return nil
	}

	return exist.(*edgeEntity.OperateEntity)
}

func (e *repoLocalOperateService) SelectOptionList(body map[string]interface{}) ([]map[string]interface{}, error) {
	// 提取业务参数
	deviceType := Map.GetString(body, "deviceType", "")
	manufacturer := Map.GetString(body, "manufacturer", "")
	operateName := Map.GetString(body, "operateName", "")

	// 简单校验参数
	if Method.HasEmpty(manufacturer) {
		return nil, errors.New("参数不能为空: manufacturer")
	}

	operateModes := make([]string, 0)
	operateModes = append(operateModes, "publish")
	operateModes = append(operateModes, "exchange")

	param := make(map[string]interface{})
	param["manufacturer"] = manufacturer
	param["operateModes"] = operateModes
	if !Method.HasEmpty(deviceType) {
		param["deviceType"] = deviceType
	}
	if !Method.HasEmpty(operateName) {
		param["operateName"] = operateName
	}

	// 转换为option格式
	data, err := e.selectEntityList(param)
	if err != nil {
		return nil, err
	}

	if !Method.HasEmpty(data) {
		resultList := make([]map[string]interface{}, 0)
		for _, entity := range data {
			operateEntity := entity.(*edgeEntity.OperateEntity)

			result := make(map[string]interface{})

			if deviceType != "" {
				if operateName == "" {
					result["value"] = operateEntity.OperateName
					result["label"] = operateEntity.OperateName
				} else {
					result["value"] = operateEntity.OperateMode
					result["label"] = operateEntity.OperateMode
				}

			}

			resultList = append(resultList, result)
		}

		return resultList, nil
	}

	return make([]map[string]interface{}, 0), nil
}
